package org.jix.gbook.auth.service.impl;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.google.common.base.Preconditions;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jix.framework.biz.context.holder.LoginUserContextHolder;
import org.jix.framework.common.exception.BizException;
import org.jix.framework.common.response.Response;
import org.jix.gbook.auth.constant.RedisKeyConstants;

import org.jix.gbook.auth.enums.LoginTypeEnum;
import org.jix.gbook.auth.enums.ResponseCodeEnum;
import org.jix.gbook.auth.model.vo.user.UpdatePasswordReqVO;
import org.jix.gbook.auth.model.vo.user.UserLoginReqVO;
import org.jix.gbook.auth.rpc.UserRPCService;
import org.jix.gbook.auth.service.AuthService;
import org.jix.gbook.user.dto.resp.FindUserByPhoneRspDTO;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Objects;

/**
 * @author stark
 * @date 2025/5/15 8:04
 * @description
 **/
@Slf4j
@Service
public class AuthServiceImpl implements AuthService {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private UserRPCService userRPCService;

    /**
     * 登录与注册
     * @param userLoginReqVO
     * @return
     */
    @Override
    public Response<String> loginAndRegister(UserLoginReqVO userLoginReqVO) {
        //获取手机号
        String phone = userLoginReqVO.getPhone();
        //获取登录类型
        Integer type = userLoginReqVO.getType();

        LoginTypeEnum loginTypeEnum = LoginTypeEnum.valueOf(type);

        //初始化userId
        Long userId = null;

        //判断登录类型
        switch (loginTypeEnum){
            case VERIFICATION_CODE: //验证码登录
                String verificationCode = userLoginReqVO.getCode();

                //校验入参验证码是否为空
                Preconditions.checkArgument(StringUtils.isNoneBlank(verificationCode),"没验证码？那你别进");

                //构建验证码redis key
                String key = RedisKeyConstants.buildVerificationCodeKey(phone);
                //查询存储在redis中该用户的登录验证码
                String sentCode = (String) redisTemplate.opsForValue().get(key);

                //判断用户提交的验证码和redis中保存的是否一致
                if (!StringUtils.equals(verificationCode,sentCode)){
                    throw new BizException(ResponseCodeEnum.VERIFICATION_CODE_ERROR);
                }

                //RPC：调用用户服务注册用户
                Long userIDTmp = userRPCService.registerUser(phone);

                //判空
                if (Objects.isNull(userIDTmp)){
                    throw new BizException(ResponseCodeEnum.LOGIN_FAIL);
                }
                userId = userIDTmp;
                break;

            case PASSWORD: //密码登录
                String password = userLoginReqVO.getPassword();
                //RPC：调用用户服务根据手机号查询
                FindUserByPhoneRspDTO findUserByPhoneRspDTO = userRPCService.findUserByPhone(phone);
                //判断该手机号是否注册
                if (Objects.isNull(findUserByPhoneRspDTO)){
                    throw new BizException(ResponseCodeEnum.USER_NOT_FOUND);
                }

                //获取密文密码
                String encodePassword = findUserByPhoneRspDTO.getPassword();
                //比对是否一致
                boolean isPasswordCorrect = passwordEncoder.matches(password, encodePassword);

                //如果密码不正确
                if (!isPasswordCorrect){
                    throw new BizException(ResponseCodeEnum.PHONE_OR_PASSWORD_ERROR);
                }

                userId = findUserByPhoneRspDTO.getId();
                break;

            default:
                break;
        }
        //SaToken登录用户，入参为用户ID
        StpUtil.login(userId);
        //获取token令牌
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        //返回令牌
        return Response.success(tokenInfo.tokenValue);
    }

    /**
     * 退出登录
     * @return
     */
    @Override
    public Response<?> logout() {

        Long userId = LoginUserContextHolder.getUserID();
        log.info("==> 用户退出登录, userId: {}", userId);
        //指定用户ID
        StpUtil.logout(userId);
        return Response.success();
    }

    /**
     * 修改密码
     * @param updatePasswordReqVO
     * @return
     */
    @Override
    public Response<?> updatePassword(UpdatePasswordReqVO updatePasswordReqVO) {
        //设置新密码
        String newPassword = updatePasswordReqVO.getNewPassword();
        //密码加密
        String encodePassword = passwordEncoder.encode(newPassword);

        //RPC：调用用户服务更新密码
        userRPCService.updatePassword(encodePassword);

        return Response.success();
    }
}
